import {
  CanActivate,
  ExecutionContext,
  Injectable,
  UnauthorizedException,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { JwtService } from '@nestjs/jwt';
import { Request } from 'express';
import { IS_PUBLIC_KEY } from '../decorators/public.decorator';
import type { JwtPayload } from '../../modules/auth/interfaces';

/**
 * JWT 认证守卫
 * 验证请求中的 JWT token，并将用户信息注入到 request 对象中
 */
@Injectable()
export class AuthGuard implements CanActivate {
  constructor(
    private jwtService: JwtService,
    private reflector: Reflector,
  ) { }

  /**
   * 验证请求
   */
  async canActivate(context: ExecutionContext): Promise<boolean> {
    // 检查是否标记为公开访问
    const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);

    const request = context.switchToHttp().getRequest<Request>();
    const token = this.extractTokenFromHeader(request);

    // 如果是公开接口，尝试解析 token（如果存在），但不强制要求
    if (isPublic) {
      if (token) {
        try {
          // 验证 JWT token（如果存在）
          const payload = await this.jwtService.verifyAsync<JwtPayload>(token);
          // 将用户信息注入到 request 对象中
          request.user = payload;
        } catch {
          // token 无效或过期，但不影响公开接口的访问
          request.user = undefined;
        }
      }
      return true;
    }

    // 非公开接口，必须提供有效的 token
    if (!token) {
      throw new UnauthorizedException('未提供认证令牌');
    }

    try {
      // 验证 JWT token
      const payload = await this.jwtService.verifyAsync<JwtPayload>(token);
      // 将用户信息注入到 request 对象中
      request.user = payload;
    } catch {
      throw new UnauthorizedException('认证令牌无效或已过期');
    }

    return true;
  }

  /**
   * 从请求头中提取 token
   */
  private extractTokenFromHeader(request: Request): string | undefined {
    const [type, token] = request.headers.authorization?.split(' ') ?? [];
    return type === 'Bearer' ? token : undefined;
  }
}
